package math;

import java.util.Scanner;

/**
 * Class used to represent a 3D Point
 *
 */
public class Point3D {
	// instance variables made public to allow for faster calculation (instead of using get methods)
	public double x,y,z;
	
	/**
	 * Create new point given specified x y z coordinates
	 * @param x
	 * @param y
	 * @param z
	 */
	public Point3D (double x, double y, double z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	public Point3D(Point3D p) {
	    x = p.x;
	    y = p.y;
	    z = p.z;
	}

	
	/**
	 * Create new 3d point from written string argument, for example XML data
	 * @param writtenCords
	 */
	public Point3D (String writtenCords) {
		Scanner scan = new Scanner(writtenCords);
		this.x = scan.nextDouble();
		this.y = scan.nextDouble();
		this.z = scan.nextDouble();
	}
	
	/**
	 * Generic constructor, coordinates will be changed at a later point
	 */
	public Point3D() {
		this.x = 0;
		this.y = 0;
		this.z = 0;
	}
	
	/**
	 * Function to calculate the distance between two 3D Points
	 * @param point2, another 3D point
	 * @return, the distance between the two points (double)
	 */
	public double DistanceBetween (Point3D point2) {
		return Math.sqrt(Math.pow(this.x - point2.x, 2) 
				+ Math.pow(this.y - point2.y, 2)
				+ Math.pow(this.z - point2.z, 2)); 
	
	}
	
	/**
	 * Function to determine whether this point is the same as another point by comparing coordinates
	 * @param point2, another 3d point
	 * @return, true if the two points have the same coordinates, false otherwise
	 */
	public boolean isEqual (Point3D point2) {
		return (this.x == point2.x 
				&& this.y == point2.y
				&& this.z == point2.z);
	}
	
	/**
	 * Subtract p1's values from p2's values
	 * @param point1
	 * @param point2
	 * @return, the vector result of the subtraction
	 */
	public static Vec subtractPoints(Point3D point1, Point3D point2) {
		return new Vec(point2, point1);
	}
	
	/**
	 * Compares two points and determines if they are the same
	 * @param point1, a 3D point
	 * @param point2, a second 3D point
	 * @return, true if the two points have the same coordinates, false otherwise
	 */
	public static boolean areEqual(Point3D point1, Point3D point2) {
		// compared point values directly instead of calling isEqual to increase time efficiency
		return ((point1.x == point2.x)
				&& (point1.y == point2.y)
				&& (point1.z == point2.z));
	}
	
	public static Vec sub(Vec a, Point3D b) {
	        return new Vec(a.x - b.x, a.y - b.y, a.z - b.z);
	}
 

	public static Vec sub(Point3D a, Point3D b) {
		return new Vec(a.x - b.x, a.y - b.y, a.z - b.z);
    }
	
	public void add(Vec a) {
        x += a.x;
        y += a.y;
        z += a.z;
    }
	
	public static Point3D add(Vec a, Point3D b) {
		Point3D p = new Point3D();
        p.x = a.x + b.x;
        p.y = a.y + b.y;
        p.z = a.z + b.z;
        return p;
    }
	
	public Vec sub(Point3D p) {
        return new Vec(x - p.x, y - p.y, z - p.z);
    }

	public void mac(double s, Vec a) {
	    x += s * a.x;
	    y += s * a.y;
	    z += s * a.z;
    }
	
	public static Point3D nearestIntersectionPoint(Ray ray, double distance) {
		return new Point3D (
				ray.p.x + distance * ray.v.x, 
				ray.p.y + distance * ray.v.y, 
				ray.p.z + distance * ray.v.z);
	}
}


